package com.briup.pai.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.briup.pai.common.constant.LoginConstant;
import com.briup.pai.common.enums.ResultCodeEnum;
import com.briup.pai.common.enums.UserStatusEnum;
import com.briup.pai.common.exception.BriupAssert;
import com.briup.pai.common.utils.JwtUtil;
import com.briup.pai.common.utils.MessageUtil;
import com.briup.pai.common.utils.RedisUtil;
import com.briup.pai.common.utils.SecurityUtil;
import com.briup.pai.convert.UserConvert;
import com.briup.pai.dao.UserMapper;
import com.briup.pai.entity.dto.LoginWithPhoneDTO;
import com.briup.pai.entity.dto.LoginWithUsernameDTO;
import com.briup.pai.entity.po.User;
import com.briup.pai.entity.vo.CurrentLoginUserVO;
import com.briup.pai.service.ILoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserServiceImpl userServiceImpl;
    @Autowired
    private UserConvert userConvert;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public String loginWithUsername(LoginWithUsernameDTO dto) {
        //登录逻辑
        //获取username和password进行查询
        String username = dto.getUsername();
        String password = dto.getPassword();

        //要求查询的user不能为空
        User user = BriupAssert.requireNotNull(userServiceImpl,User::getUsername,username,ResultCodeEnum.USER_NOT_EXIST);

        //password必须正确
        BriupAssert.requireEqual(user.getPassword(), DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8)),
                ResultCodeEnum.PASSWORD_IS_WRONG);

        // 账号状态必须可用
        BriupAssert.requireEqual(user.getStatus(),
                UserStatusEnum.AVAILABLE.getStatus(),  // 0
                ResultCodeEnum.USER_IS_DISABLED);
//        //使用mp进行查询
//        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//        lqw.eq(User::getUsername, username).eq(User::getPassword, password);
//        User user = userMapper.selectOne(lqw);
        //判断user有效性
//        if(user == null){
//            throw new CustomException(ResultCodeEnum.USER_NOT_EXIST);
//        }
        //将user信息转化为jwt字符串返回
        HashMap<String, Object> map = new HashMap<>();
        map.put(LoginConstant.JWT_PAYLOAD_KEY, user.getId());
        return JwtUtil.generateJwt(map);


    }

    @Override
    public CurrentLoginUserVO getCurrentUser() {
        //从TheadLocal中获取用户id
        Integer id = SecurityUtil.getUserId();
        User user = userMapper.selectById(id);
        return userConvert.po2CurrentLoginUserVO(user);

    }

    @Override
    public void sendMessageCode(String telephone) {

        //发送手机短信，接收验证码  ，将验证码保存到redis
        //1.保存到redis的key与time
        String key = LoginConstant.USER_SMS_VERIFY_CODE_PREFIX + telephone;
        long time = LoginConstant.USER_SMS_VERIFY_CODE_EXPIRATION_TIME;
        //验证用户、用户状态、验证码是否过期，是否重复
        User user = BriupAssert.requireNotNull(userServiceImpl, User::getTelephone, telephone, ResultCodeEnum.USER_NOT_EXIST);
        BriupAssert.requireEqual(user.getStatus(), UserStatusEnum.AVAILABLE.getStatus(), ResultCodeEnum.USER_IS_DISABLED);
        BriupAssert.requireFalse(redisUtil.exist(key), ResultCodeEnum.USER_VERIFY_CODE_ALREADY_EXIST);
        //2.生成验证码，使用hutools工具
        Integer value = RandomUtil.randomInt(1000, 9999);
        try {
            MessageUtil.sendMessage(telephone, 1234);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        redisUtil.set(key,value, time);

    }

    @Override
    public String loginWithTelephone(LoginWithPhoneDTO dto) {
        //验证手机号和redis中的验证码是否匹配
        //获取手机号
        String telephone = dto.getTelephone();
        //获取验证码
        Integer code = dto.getCode();
        //验证telephone的对象
        User user = BriupAssert.requireNotNull(userServiceImpl, User::getTelephone, telephone, ResultCodeEnum.USER_NOT_EXIST);
        //确保user状态可用
        BriupAssert.requireEqual(user.getStatus(), UserStatusEnum.AVAILABLE.getStatus(), ResultCodeEnum.USER_IS_DISABLED);
        //和redis里的key和value对比
        String key = LoginConstant.USER_SMS_VERIFY_CODE_PREFIX + telephone;
        //确保key在redis必须存在
        BriupAssert.requireTrue(redisUtil.exist(key), ResultCodeEnum.USER_VERIFY_CODE_NOT_EXIST);
        Integer value = (Integer) redisUtil.get(key);
        //验证value和code
        BriupAssert.requireEqual(value, code, ResultCodeEnum.USER_VERIFY_CODE_ERROR);
        //删除redis中的key
        redisUtil.remove(key);
        //返回jwt字符串
        HashMap<String, Object> map = new HashMap<>();
        map.put(LoginConstant.JWT_PAYLOAD_KEY, user.getId());
        return JwtUtil.generateJwt(map);

    }
}